package pokerantani.v2.model;

public class Card implements Comparable<Card>, Cloneable {
	/* numeric values, according to
	 * Poker Hand Dataset from UCI[1]
	 * [1]: http://archive.ics.uci.edu/ml/machine-learning-databases/poker/ 
	 */
	
	public static final int HEARTS = 1;
	public static final int SPADES = 2;
	public static final int DIAMONDS = 3;
	public static final int CLUBS = 4;
	
	public static final int ACE = 1;
	public static final int TEN = 10;
	public static final int JACK = 11;
	public static final int QUEEN = 12;
	public static final int KING = 13;
	
	public static final int _H = HEARTS;
	public static final int _S = SPADES;
	public static final int _D = DIAMONDS;
	public static final int _C = CLUBS;
	
	public static final int _A = ACE;
	public static final int _T = TEN;
	public static final int _J = JACK;
	public static final int _Q = QUEEN;
	public static final int _K = KING;

	public final int rank;
	public final int suit;
	
	public Card(int rank, int suit) {
		this.rank = rank;
		this.suit = suit;
	}
	
	public Card(String str) {
		if(str.length() == 2) {
			this.rank = rankFromString(str.substring(0, 1));
			this.suit = suitFromString(str.substring(1, 2));
		} else {
			throw new IllegalArgumentException("Bad card representation: '" + str + "'");
		}
	}
	
	public static String rankToString(int rank) {
		switch(rank) {
		case _A: return "A";
		case _T: return "T";
		case _J: return "J";
		case _Q: return "Q";
		case _K: return "K";
		default: if(rank > _A && rank <= _K) return "" + rank;
		}
		return "?";
	}
	
	public static int rankFromString(String rank) {
		if(rank.equalsIgnoreCase("A")) return _A;
		else if(rank.equalsIgnoreCase("T")) return _T;
		else if(rank.equalsIgnoreCase("J")) return _J;
		else if(rank.equalsIgnoreCase("Q")) return _Q;
		else if(rank.equalsIgnoreCase("K")) return _K;
		else return Integer.parseInt(rank);
	}
	
	public static String suitToString(int suit) {
		switch(suit) {
		case _H: return "H";
		case _S: return "S";
		case _D: return "D";
		case _C: return "C";
		default: return "?";
		}
	}
	
	public static int suitFromString(String suit) {
		if(suit.equalsIgnoreCase("H")) return _H;
		else if(suit.equalsIgnoreCase("S")) return _S;
		else if(suit.equalsIgnoreCase("D")) return _D;
		else if(suit.equalsIgnoreCase("C")) return _C;
		else return 0;
	}
	
	public String toString() {
		return rankToString(rank) + suitToString(suit);
	}
	
	@Override
	public boolean equals(Object obj) {
		if(obj == null) return false;
		if(obj instanceof Card) {
			Card c = (Card)obj;
			return c.rank == rank && c.suit == suit;
		} else return false;
	}
	
	@Override
	public int hashCode() {
		return 17 * suit + 103 * rank;
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return new Card(rank, suit);
	}
	
	@Override
	public int compareTo(Card o) {
		int pokerSuitRankings[] = {0, 30, 40, 20, 10};
		if(o.rank == rank) {
			return new Integer(pokerSuitRankings[suit]).compareTo(pokerSuitRankings[o.suit]);
		} else {
			return new Integer(rank).compareTo(o.rank);
		}
	}
}